package com.atguigu.gmall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.entity.CartInfo;
import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.UserAuthUtil;
import com.atguigu.gmall.feign.product.ProductSkuDataFeign;
import com.atguigu.gmall.product.entity.SkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductSkuDataFeign productSkuDataFeign;

    /**
     * 判断是临时登录还是用户登录
     *
     * @return
     */
    @Override
    public String determinCartKey() {
        //TODO 同一个线程调用
        HttpServletRequest request = UserAuthUtil.request();
        String userId = request.getHeader(RedisConst.USER_ID_HEADER);
        if (!StringUtils.isEmpty(userId)) {
            //用户登陆了
            return RedisConst.CART_INFO_KEY + userId;
        }
        //说明没登录
        String tempId = request.getHeader(RedisConst.TEMP_ID_HEADER);
        return RedisConst.CART_INFO_KEY + tempId;
    }

    /**
     * 添加到购物车
     *
     * @param skuId
     * @param skuNum
     * @return
     */
    @Override
    public SkuInfo addCart(Long skuId, Integer skuNum, String cartKey) {
        //从redis中拿到商品，以前的购物车是否有这个商品
        CartInfo info = getItem(cartKey,skuId);
        //1没有添加
        if (info == null) {
            CartInfo itemToSave = prepareCartInfo(skuId, skuNum);
            //保存redis
            saveItem(cartKey, itemToSave);
            //给前端返回数据
            SkuInfo skuInfo = convertItemToSkuInfo(itemToSave);
            return skuInfo;
        } else {
            //2 有 修改数量
            info.setSkuNum(info.getSkuNum() + skuNum);
            info.setUpdateTime(new Date());
            BigDecimal price = productSkuDataFeign.getPrice(skuId).getData();
            info.setSkuPrice(price);
            //保存redis
            saveItem(cartKey, info);
            SkuInfo skuInfo = convertItemToSkuInfo(info);
            return skuInfo;
        }

    }

    private SkuInfo convertItemToSkuInfo(CartInfo itemToSave) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setSkuName(itemToSave.getSkuName());
        skuInfo.setSkuDefaultImg(itemToSave.getImgUrl());
        skuInfo.setId(itemToSave.getSkuId());
        return skuInfo;
    }

    private CartInfo prepareCartInfo(Long skuId, Integer skuNum) {
        SkuInfo skuInfo = productSkuDataFeign.getSkuInfo(skuId).getData();
        CartInfo itemToSave = new CartInfo();
        itemToSave.setSkuId(skuInfo.getId());
        itemToSave.setCartPrice(skuInfo.getPrice());
        itemToSave.setSkuPrice(skuInfo.getPrice());
        itemToSave.setSkuNum(skuNum);
        itemToSave.setImgUrl(skuInfo.getSkuDefaultImg());
        itemToSave.setSkuName(skuInfo.getSkuName());
        itemToSave.setIsChecked(1);
        itemToSave.setCreateTime(new Date());
        itemToSave.setUpdateTime(new Date());
        return itemToSave;
    }

    /**
     * 从购物车中拿到商品
     * @param cartKey
     * @param skuId
     * @return
     */
    @Override
    public CartInfo getItem(String cartKey,Long skuId) {
        //1 拿到商品
        Object item = redisTemplate.opsForHash()
                .get(cartKey, skuId.toString());
        if(item==null){
            return  null;
        }
        String json = item.toString();
        //2如果有就逆转
        CartInfo cartInfo = JSON.parseObject(json, CartInfo.class);
        return cartInfo;
    }




    @Override
    public void saveItem(String cartKey, CartInfo item) {
        //单个商品 不得超过 100
        if (item.getSkuNum()>=RedisConst.CART_ITEM_NUM_LIMIT) {
            throw  new GmallException(ResultCodeEnum.CART_ITEM_NUM_OVERFLOW);
        }
        // TODO 购物车商品量总和不能超过 100
        Long size = redisTemplate.opsForHash().size(cartKey);
        Boolean aBoolean = redisTemplate.opsForHash()
                .hasKey(cartKey, item.getSkuId().toString());
        if(!aBoolean){
            if (size+1 >=100){
                throw  new GmallException(ResultCodeEnum. CART_ITEM_COUNT_OVERFLOW);
            }
        }
        redisTemplate.opsForHash()
                .put(cartKey, item.getSkuId().toString(), JSON.toJSONString(item));
    }

    /**
     * 查询购物车的商品列表
     * @param cartKey
     * @return
     */
    @Override
    public List<CartInfo> getCartItems(String cartKey) {
        //获取map中的所有值
        List<CartInfo> cartInfos = redisTemplate.opsForHash()
                .values(cartKey)
                .stream()
                .map(item -> JSON.parseObject(item.toString(), CartInfo.class))
                .sorted((o1,o2)->o2.getCreateTime().compareTo(o1.getCreateTime()))//以创建时间进行排序
                .collect(Collectors.toList());
            //TODO 同步最新价格
        CompletableFuture.runAsync(()->{
            sysncPrice(cartKey, cartInfos);
        });

        return cartInfos;
    }

    private void sysncPrice(String cartKey, List<CartInfo> cartInfos) {
        //进行节流操作
        Long increment = redisTemplate.opsForValue().increment("price-increment" + cartKey);
        if (increment % 10 == 0) {
            cartInfos.stream().forEach(item -> {
                        //查看价格
                        BigDecimal realPrice = productSkuDataFeign.getPrice(item.getSkuId()).getData();
                        // TODO 这样价格发生变化
                        if (Math.abs(item.getSkuPrice().doubleValue() - realPrice.doubleValue()) >= 0.0001) {
                            log.info("价格发生变化 {}，价格最新变化为{}", cartKey, item);
                            item.setSkuPrice(realPrice);
                            saveItem(cartKey, item);
                        }

                    }
            );
        }
    }
    @Override
    public void updateItemNum(String cartKey, Long skuId, Integer skuNum) {
        //从购物车中拿到这个商品
        CartInfo cartInfo = getItem(cartKey, skuId);
        //修改购物车商品的数量
        if(skuNum==1||skuNum==-1) {
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
        }else{
            cartInfo.setSkuNum(skuNum);
        }

        //保存到购物车
        saveItem(cartKey,cartInfo);

    }

    @Override
    public void updateChecked(String cartKey, Long skuId, Integer checked) {
        if(!(checked==1||checked==0)){
            throw  new GmallException(ResultCodeEnum. INVAILD_PARAM);
        }
        CartInfo info = getItem(cartKey, skuId);
        //修改状态
        info.setIsChecked(checked);
        //保存到redis中
        saveItem(cartKey,info);

    }

    /**
     * 删除购物车某一列
     * @param cartKey
     * @param skuId
     */

    @Override
    public void deleteCart(String cartKey, Long skuId) {
        //删除
        redisTemplate.opsForHash().delete(cartKey,skuId.toString());
    }

    @Override
    public List<CartInfo> displayItems() {
        //判断用户是否登陆了 临时购物车要有数据
        //1 获取临时购物车的key
        String tempCartKey= getCustomerCatkey (RedisConst.TEMP_ID_HEADER);
       //2  获取用户购物车的key
        String  userCartKey= getCustomerCatkey(RedisConst.USER_ID_HEADER);
        //用户购物车没登录
       if(userCartKey==null){
           //TODO  设置过期时间
           Long expire = redisTemplate.getExpire(tempCartKey);
           if(expire<0){
               redisTemplate.expire(tempCartKey,12, TimeUnit.DAYS);
           }
            //TODO 返回临时用户购物车
            return  getCartItems(tempCartKey);
        }

        //用户登录是否需要合并
        //TODO 判断购物车里面是否有东西\
        try{ Long size = redisTemplate.opsForHash().size(tempCartKey);
            if(size>0){
                //TODO 需要合并  将临时购物车中的商品通过遍历都拿出来 放入登录的用户购物车中
                List<CartInfo> cartItems = getCartItems(tempCartKey);
                for (CartInfo item : cartItems) {
                    addCart(item.getSkuId(),item.getSkuNum(),userCartKey);
                }
                //TODO  完成合并将临时购物车删除
                redisTemplate.delete(tempCartKey);
            }}catch (Exception e){
            // 合并期间出错 要把这些异常吃掉
            //TODO 为了展示真唱执行
        }
        //TODO 临时购物车有就合并 ，临时购物车没有返回的还是用户购物车
        List<CartInfo> cartItems = getCartItems(userCartKey);
        return  getCartItems(userCartKey);
    }

    @Override
    public List<CartInfo> getChecked(String cartKey) {
        // 拿到商品 //TODO 直接调用拿到商品会出现bug
       // List<CartInfo> items = getCartItems(cartKey);
        List<CartInfo> collect = redisTemplate.opsForHash().values(cartKey)
                .stream()
                .map(item -> JSON.parseObject(item.toString(), CartInfo.class))
                .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                .filter((o1) -> o1.getIsChecked() == 1)
                .collect(Collectors.toList());
//        List<CartInfo> infoList = items.stream()
//                .filter((o1) -> o1.getIsChecked() == 1)
//                .collect(Collectors.toList());
        return collect;
    }

    @Override
    public void deleteChecked(String cartKey) {
        List<CartInfo> checkeds = getChecked(cartKey);
        List<String> collect = checkeds.stream()
                .map(item -> item.getSkuId().toString())
                .collect(Collectors.toList());
        //TODO 如果删除很快运行完成，而同步线程后台运行很慢，就会导致删除不掉

        redisTemplate.opsForHash().delete(cartKey, collect.toArray());
    }

    private String getCustomerCatkey (String flag) {
        HttpServletRequest request = UserAuthUtil.request();
        String header = request.getHeader(flag);
        if(StringUtils.isEmpty(header)){
            return  null;
        }
     return   RedisConst.CART_INFO_KEY+header;
    }


}
